﻿using HelperFromTheSkeleton.ExtendMethod;
using System.Collections.Concurrent;
using System.Reflection;

namespace HelperFromTheSkeleton.CacheHelper
{
    public class CacheManage
    {
        private ConcurrentDictionary<string, object> _keyValuePairs;
        private ConcurrentDictionary<string, DateTime> _expirationTime;
        private bool isTimeInspect = false;

        public CacheManage()
        {
            _keyValuePairs = new ConcurrentDictionary<string, object>();
            _expirationTime = new ConcurrentDictionary<string, DateTime>();
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="data"></param>
        public void Add(string key, Object data)
        {
            TimeInspect();
            if (!_keyValuePairs.TryGetValue(key, out _))
            {
                if (!_keyValuePairs.TryAdd(key, data))
                {
                    throw new InvalidOperationException("添加缓存失败");
                }
            }
            else
            {
                throw new InvalidOperationException("添加缓存时Key重复");
            }
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="key"></param>
        /// <param name="data"></param>
        public void Add(string key, Object data, int hour = 0, int minutes = 0,int seconds =0)
        {
            TimeInspect();
            if (!_keyValuePairs.TryGetValue(key, out _))
            {
                if (!_keyValuePairs.TryAdd(key, data))
                {
                    throw new InvalidOperationException("添加缓存失败");
                }
                else
                {
                    var time = DateTime.Now.AddHours(hour).AddMinutes(minutes).AddSeconds(seconds);
                    _expirationTime.TryAdd(key, time);
                }
            }
            else
            {
                throw new InvalidOperationException("添加缓存时Key重复");
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="key"></param>
        /// <param name="data"></param>
        public void Updata(string key, Object data)
        {
            TimeInspect();
            if (_keyValuePairs.TryGetValue(key, out object? oldValue))
            {
                if (!_keyValuePairs.TryUpdate(key, data, oldValue))
                {
                    throw new InvalidOperationException("缓存更新失败");
                }
            }
            else
            {
                throw new InvalidOperationException("更新缓存时找不到对应的键值");
            }
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            TimeInspect();
            if (_keyValuePairs.TryGetValue(key, out _))
            {
                if (!_keyValuePairs.TryRemove(key, out _))
                {
                    throw new InvalidOperationException("删除缓存时出错");
                }
            }
        }

        public T? Get<T>(string key)
        {
            TimeInspect();
            if (_keyValuePairs.TryGetValue(key, out object? value))
            {
                if (_expirationTime.TryGetValue(key, out DateTime Datevalue))
                {
                    var nowTime = DateTime.Now;
                    if (Datevalue < nowTime)
                    {
                        if (_keyValuePairs.TryGetValue(key, out _))
                        {
                            _keyValuePairs.TryRemove(key, out _);
                        }
                        _expirationTime.TryRemove(key, out _);
                        return default;
                    }
                }
                return (T)value;
            }
            return default(T);
        }

        /// <summary>
        /// 获取深度拷贝
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T? GetDeepCopy<T>(string key)
        {
            TimeInspect();
            if (_keyValuePairs.TryGetValue(key, out object? value))
            {
                if (_expirationTime.TryGetValue(key, out DateTime Datevalue))
                {
                    var nowTime = DateTime.Now;
                    if (Datevalue < nowTime)
                    {
                        if (_keyValuePairs.TryGetValue(key, out _))
                        {
                            _keyValuePairs.TryRemove(key, out _);
                        }
                        _expirationTime.TryRemove(key, out _);
                        return default;
                    }
                }
                var type = typeof(T);
                if (type.FullName == null) return default;
                var obj = type.Assembly.CreateInstance(type.FullName);
                if(obj == null) return default; 
                obj.CopyProperty(value);
                return (T)obj;
            }
            return default;
        }
        

        private void TimeInspect()
        {
            if (!isTimeInspect)
            {
                isTimeInspect = true;
                Task.Run(() =>
                {
                    var nowTime = DateTime.Now;
                    var keys = _expirationTime.Keys;
                    foreach (var val in keys)
                    {
                        if (_expirationTime.TryGetValue(val, out DateTime value))
                        {
                            if (value < nowTime)
                            {
                                if (_keyValuePairs.TryGetValue(val, out _))
                                {
                                    _keyValuePairs.TryRemove(val, out _);
                                }
                                _expirationTime.TryRemove(val, out _);
                            }
                        }
                    }
                });
            }
        }
    }
}
